#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <cstdint>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>

#define MAX_BLOCKLOG 1024
class Socket
{
private:
    int _sockfd;

public:
    Socket() : _sockfd(-1) {}
    Socket(int fd) : _sockfd(fd) {}
    ~Socket() { Close(); }

    int Fd() { return _sockfd; }

    // 创建套接字
    bool Create()
    {
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            std::cerr << "socket create failed!" << std::endl;
            return false;
        }
        return true;
    }

    // 绑定地址信息
    bool Bind(const std::string &ip, uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());

        int ret = ::bind(_sockfd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0)
            return false;
        return true;
    }

    // 开始监听
    bool Listen(int n = MAX_BLOCKLOG)
    {
        int ret = ::listen(_sockfd, n);
        if (ret < 0)
        {
            std::cerr << "listen failed, sockfd: " << _sockfd << "!" << std::endl;
            return false;
        }
        return true;
    }

    // 向服务器发起连接
    bool Connect(const std::string &ip, uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        int ret = ::connect(_sockfd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0)
        {
            std::cerr << "connect " << ip << ":" << port << " failed" << std::endl;
            return false;
        }
        return true;
    }

    // 获取新连接
    int Accept()
    {
        int newfd = ::accept(_sockfd, NULL, NULL);
        if (newfd < 0)
            std::cerr << "accept failed!" << std::endl;
        return newfd;
    }

    // 接收数据
    ssize_t Recv(int sockfd, void *buf, size_t len, int flag = 0)
    {
        ssize_t ret = ::recv(sockfd, buf, len, flag);
        if (ret < 0)
        {
            // EAGAIN 当前socket的接收缓冲区中没有数据了，在非阻塞的情况下才会有这个错误
            // EINTR  表示当前socket的阻塞等待，被信号打断了
            if (errno == EAGAIN || errno == EINTR)
                return 0;
            std::cerr << "recv error!" << errno << std::endl;
            return -1;
        }
        return ret;
    }

    ssize_t Recv(void *buf, size_t len, int flag = 0)
    {
        ssize_t ret = ::recv(_sockfd, buf, len, flag);
        if (ret < 0)
        {
            // EAGAIN 当前socket的接收缓冲区中没有数据了，在非阻塞的情况下才会有这个错误
            // EINTR  表示当前socket的阻塞等待，被信号打断了
            if (errno == EAGAIN || errno == EINTR)
                return 0;
            std::cerr << "recv error!" << errno << std::endl;
            return -1;
        }
        return ret;
    }

    ssize_t NonBlockRecv(int sockfd, void *buf, size_t len)
    {
        return Recv(sockfd, buf, len, MSG_DONTWAIT);
    }

    ssize_t NonBlockRecv(void *buf, size_t len)
    {
        return Recv(buf, len, MSG_DONTWAIT);
    }

    // 发送数据
    ssize_t Send(const void *buf, size_t len, int flag = 0)
    {
        ssize_t ret = ::send(_sockfd, buf, len, flag);
        if (ret <= 0)
        {
            // EAGAIN 当前socket的接收缓冲区中没有数据了，在非阻塞的情况下才会有这个错误
            // EINTR  表示当前socket的阻塞等待，被信号打断了
            if (errno == EAGAIN || errno == EINTR)
                return 0;
            std::cerr << "send error!" << errno << std::endl;
            return -1;
        }
        return ret;
    }

    ssize_t Send(int sockfd, void *buf, size_t len, int flag = 0)
    {
        ssize_t ret = ::send(sockfd, buf, len, flag);
        if (ret <= 0)
        {
            // EAGAIN 当前socket的接收缓冲区中没有数据了，在非阻塞的情况下才会有这个错误
            // EINTR  表示当前socket的阻塞等待，被信号打断了
            if (errno == EAGAIN || errno == EINTR)
                return 0;
            std::cerr << "send error!" << errno << std::endl;
            return -1;
        }
        return ret;
    }

    ssize_t NonBlockSend(int sockfd, void *buf, size_t len)
    {
        if (len == 0)
            return 0;
        return Send(sockfd, buf, len, MSG_DONTWAIT);
    }

    ssize_t NonBlockSend(void *buf, size_t len)
    {
        if (len == 0)
            return 0;
        return Send(buf, len, MSG_DONTWAIT);
    }

    // 关闭套接字
    void Close()
    {
        if (_sockfd != -1)
        {
            ::close(_sockfd);
            _sockfd = -1;
        }
    }

    // 创建一个服务器连接
    bool CreateServer(uint16_t port, bool block_flag = false, const std::string &ip = "0.0.0.0")
    {
        // 1. 创建套接字，2. 绑定地址，3. 开始监听，4. 设置非阻塞， 5. 启动地址重用
        if (!Create())
            return false;
        if (block_flag)
            NonBlock();
        ReuseAddress();
        if (!Bind(ip, port))
            return false;
        if (!Listen())
            return false;
        
        return true;
    }

    // 创建一个客户端连接
    bool CreateClient(uint16_t port, const std::string &ip)
    {
        if (!Create())
            return false;
        if (!Connect(ip, port))
            return false;
        return true;
    }

    // 设置套接字选项---开启地址端口重用
    void ReuseAddress()
    {
        // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
        int val = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int));
        val = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int));
    }

    // 设置套接字阻塞属性-- 设置为非阻塞
    void NonBlock()
    {
        // int fcntl(int fd, int cmd, ... /* arg */ );
        int flag = fcntl(_sockfd, F_GETFL, 0);
        fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
    }
};